

<!doctype html>

<html lang="en" data-content_root="../../">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>skidl.utilities &#8212; SKiDL 1.2.2 documentation</title>
    <link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=fa44fd50" />
    <link rel="stylesheet" type="text/css" href="../../_static/bizstyle.css?v=a66e137f" />
    
    <script src="../../_static/documentation_options.js?v=fd7cadf9"></script>
    <script src="../../_static/doctools.js?v=9a2dae69"></script>
    <script src="../../_static/sphinx_highlight.js?v=dc90522c"></script>
    <script src="../../_static/bizstyle.js"></script>
    <link rel="index" title="Index" href="../../genindex.html" />
    <link rel="search" title="Search" href="../../search.html" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <!--[if lt IE 9]>
    <script src="_static/css3-mediaqueries.js"></script>
    <![endif]-->
  </head><body>
    <h1 id="site-title"><a href="../../../../"><img src="../../../../images/slim_banner.png" width="100%"></a></h1>
    
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../../genindex.html" title="General Index"
             accesskey="I">index</a></li>
        <li class="right" >
          <a href="../../py-modindex.html" title="Python Module Index"
             >modules</a> |</li>
        <li class="nav-item nav-item-0"><a href="../../index.html">SKiDL 1.2.2 documentation</a> &#187;</li>
          <li class="nav-item nav-item-1"><a href="../index.html" accesskey="U">Module code</a> &#187;</li>
        <li class="nav-item nav-item-this"><a href="">skidl.utilities</a></li> 
      </ul>
    </div>  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body" role="main">
            
  <h1>Source code for skidl.utilities</h1><div class="highlight"><pre>
<span></span><span class="c1"># -*- coding: utf-8 -*-</span>

<span class="c1"># The MIT License (MIT) - Copyright (c) Dave Vandenbout.</span>

<span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Utility functions used by the rest of SKiDL.</span>
<span class="sd">&quot;&quot;&quot;</span>

<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="p">(</span>  <span class="c1"># isort:skip</span>
    <span class="n">absolute_import</span><span class="p">,</span>
    <span class="n">division</span><span class="p">,</span>
    <span class="n">print_function</span><span class="p">,</span>
    <span class="n">unicode_literals</span><span class="p">,</span>
<span class="p">)</span>

<span class="k">try</span><span class="p">:</span>
    <span class="kn">from</span> <span class="nn">future</span> <span class="kn">import</span> <span class="n">standard_library</span>
    <span class="n">standard_library</span><span class="o">.</span><span class="n">install_aliases</span><span class="p">()</span>
<span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
    <span class="k">pass</span>


<span class="kn">import</span> <span class="nn">collections</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">os.path</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">traceback</span>
<span class="kn">import</span> <span class="nn">urllib.parse</span>
<span class="kn">import</span> <span class="nn">urllib.request</span>
<span class="kn">from</span> <span class="nn">builtins</span> <span class="kn">import</span> <span class="nb">chr</span><span class="p">,</span> <span class="nb">dict</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">open</span><span class="p">,</span> <span class="nb">range</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="nb">super</span>
<span class="kn">from</span> <span class="nn">contextlib</span> <span class="kn">import</span> <span class="n">contextmanager</span>

<span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;INDEX_SEPARATOR&quot;</span><span class="p">,</span> <span class="s2">&quot;export_to_all&quot;</span><span class="p">]</span>


<span class="sd">&quot;&quot;&quot;Separator for strings containing multiple indices.&quot;&quot;&quot;</span>
<span class="n">INDEX_SEPARATOR</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="s2">&quot;[, </span><span class="se">\t</span><span class="s2">]+&quot;</span><span class="p">)</span>


<div class="viewcode-block" id="export_to_all">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.export_to_all">[docs]</a>
<span class="k">def</span> <span class="nf">export_to_all</span><span class="p">(</span><span class="n">fn</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Add a function to the __all__ list of this module.</span>

<span class="sd">    Args:</span>
<span class="sd">        fn (function): The function to be added to the __all__ list of this module.</span>

<span class="sd">    Returns:</span>
<span class="sd">        function: The function that was passed in.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">mod</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="p">[</span><span class="n">fn</span><span class="o">.</span><span class="vm">__module__</span><span class="p">]</span>
    <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">mod</span><span class="p">,</span> <span class="s2">&quot;__all__&quot;</span><span class="p">):</span>
        <span class="n">mod</span><span class="o">.</span><span class="n">__all__</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">fn</span><span class="o">.</span><span class="vm">__name__</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">mod</span><span class="o">.</span><span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="n">fn</span><span class="o">.</span><span class="vm">__name__</span><span class="p">]</span>
    <span class="k">return</span> <span class="n">fn</span></div>



<div class="viewcode-block" id="Rgx">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.Rgx">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">class</span> <span class="nc">Rgx</span><span class="p">(</span><span class="nb">str</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Same as a string but the class makes it recognizable as as a regular expression.&quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">s</span><span class="p">):</span>
        <span class="nb">str</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">s</span><span class="p">)</span></div>



<div class="viewcode-block" id="sgn">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.sgn">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">sgn</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Return -1,0,1 if x&lt;0, x==0, x&gt;0.&quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span> <span class="k">if</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="k">else</span> <span class="p">(</span><span class="mi">1</span> <span class="k">if</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="k">else</span> <span class="mi">0</span><span class="p">)</span></div>



<div class="viewcode-block" id="debug_trace">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.debug_trace">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">debug_trace</span><span class="p">(</span><span class="n">fn</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Decorator to print tracing info when debugging execution.&quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="nf">traced_fn</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;debug_trace&quot;</span><span class="p">):</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Doing </span><span class="si">{}</span><span class="s2"> ...&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">fn</span><span class="o">.</span><span class="vm">__name__</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">fn</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">traced_fn</span></div>



<div class="viewcode-block" id="num_to_chars">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.num_to_chars">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">num_to_chars</span><span class="p">(</span><span class="n">num</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Return a string like &#39;AB&#39; when given a number like 28.&quot;&quot;&quot;</span>
    <span class="n">num</span> <span class="o">-=</span> <span class="mi">1</span>
    <span class="n">s</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
    <span class="k">while</span> <span class="n">num</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">:</span>
        <span class="n">s</span> <span class="o">=</span> <span class="nb">chr</span><span class="p">(</span><span class="nb">ord</span><span class="p">(</span><span class="s2">&quot;A&quot;</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="n">num</span> <span class="o">%</span> <span class="mi">26</span><span class="p">))</span> <span class="o">+</span> <span class="n">s</span>
        <span class="n">num</span> <span class="o">=</span> <span class="n">num</span> <span class="o">//</span> <span class="mi">26</span> <span class="o">-</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="n">s</span></div>



<div class="viewcode-block" id="rmv_quotes">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.rmv_quotes">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">rmv_quotes</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Remove starting and ending quotes from a string.&quot;&quot;&quot;</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">basestring</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">s</span>

    <span class="n">mtch</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;^\s*&quot;(.*)&quot;\s*$&#39;</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">mtch</span><span class="p">:</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">s</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="n">mtch</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span>
        <span class="k">except</span> <span class="p">(</span><span class="ne">AttributeError</span><span class="p">,</span> <span class="ne">LookupError</span><span class="p">):</span>
            <span class="n">s</span> <span class="o">=</span> <span class="n">mtch</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">s</span></div>



<div class="viewcode-block" id="add_quotes">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.add_quotes">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">add_quotes</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Return string with added quotes if it contains whitespace or parens.&quot;&quot;&quot;</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">basestring</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">s</span>

    <span class="c1"># Remove quotes if string already has them.</span>
    <span class="n">s</span> <span class="o">=</span> <span class="n">rmv_quotes</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;[\s()]&quot;</span><span class="p">,</span> <span class="n">s</span><span class="p">):</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">s</span> <span class="o">=</span> <span class="s1">&#39;&quot;&#39;</span> <span class="o">+</span> <span class="n">s</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;&quot;&#39;</span>
        <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
            <span class="n">s</span> <span class="o">=</span> <span class="s1">&#39;&quot;&#39;</span> <span class="o">+</span> <span class="n">s</span> <span class="o">+</span> <span class="s1">&#39;&quot;&#39;</span>

    <span class="k">return</span> <span class="n">s</span></div>



<div class="viewcode-block" id="cnvt_to_var_name">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.cnvt_to_var_name">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">cnvt_to_var_name</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Convert a string to a legal Python variable name and return it.&quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;\W|^(?=\d)&quot;</span><span class="p">,</span> <span class="s2">&quot;_&quot;</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span></div>



<div class="viewcode-block" id="to_list">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.to_list">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">to_list</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Return x if it is already a list, or return a list containing x if x is a scalar.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">,</span> <span class="nb">set</span><span class="p">)):</span>
        <span class="k">return</span> <span class="n">x</span>  <span class="c1"># Already a list, so just return it.</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">x</span><span class="p">]</span>  <span class="c1"># Wasn&#39;t a list, so make it into one.</span></div>



<div class="viewcode-block" id="list_or_scalar">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.list_or_scalar">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">list_or_scalar</span><span class="p">(</span><span class="n">lst</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Return a list if passed a multi-element list, otherwise return a single scalar.</span>

<span class="sd">    Args:</span>
<span class="sd">        lst: Either a list or a scalar.</span>

<span class="sd">    Returns:</span>
<span class="sd">        * A list if passed a multi-element list.</span>
<span class="sd">        * The list element if passed a single-element list.</span>
<span class="sd">        * None if passed an empty list.</span>
<span class="sd">        * A scalar if passed a scalar.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">)):</span>
        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">lst</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">lst</span>  <span class="c1"># Multi-element list, so return it unchanged.</span>
        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">lst</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">lst</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>  <span class="c1"># Single-element list, so return the only element.</span>
        <span class="k">return</span> <span class="kc">None</span>  <span class="c1"># Empty list, so return None.</span>
    <span class="k">return</span> <span class="n">lst</span>  <span class="c1"># Must have been a scalar, so return that.</span></div>



<div class="viewcode-block" id="flatten">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.flatten">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">flatten</span><span class="p">(</span><span class="n">nested_list</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Return a flattened list of items from a nested list.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">lst</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">nested_list</span><span class="p">:</span>
        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">,</span> <span class="nb">set</span><span class="p">)):</span>
            <span class="n">lst</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">flatten</span><span class="p">(</span><span class="n">item</span><span class="p">))</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">lst</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">lst</span></div>



<div class="viewcode-block" id="set_attr">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.set_attr">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">set_attr</span><span class="p">(</span><span class="n">objs</span><span class="p">,</span> <span class="n">attr</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Set an attribute in a list of objects.&quot;&quot;&quot;</span>
    <span class="k">for</span> <span class="n">o</span> <span class="ow">in</span> <span class="n">to_list</span><span class="p">(</span><span class="n">objs</span><span class="p">):</span>
        <span class="nb">setattr</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="n">attr</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span></div>



<div class="viewcode-block" id="rmv_attr">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.rmv_attr">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">rmv_attr</span><span class="p">(</span><span class="n">objs</span><span class="p">,</span> <span class="n">attrs</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Remove a list of attributes from a list of objects.&quot;&quot;&quot;</span>
    <span class="k">for</span> <span class="n">o</span> <span class="ow">in</span> <span class="n">to_list</span><span class="p">(</span><span class="n">objs</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">to_list</span><span class="p">(</span><span class="n">attrs</span><span class="p">):</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="nb">delattr</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
                <span class="k">pass</span></div>



<div class="viewcode-block" id="add_unique_attr">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.add_unique_attr">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">add_unique_attr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">check_dup</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Create an attribute if the attribute name isn&#39;t already used.&quot;&quot;&quot;</span>
    <span class="kn">from</span> <span class="nn">.logger</span> <span class="kn">import</span> <span class="n">active_logger</span>

    <span class="k">try</span><span class="p">:</span>
        <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">check_dup</span><span class="p">:</span>
            <span class="n">active_logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
                <span class="s2">&quot;Unable to create attribute </span><span class="si">{name}</span><span class="s2"> of type </span><span class="si">{typ1}</span><span class="s2"> because one already exists of type </span><span class="si">{typ2}</span><span class="s2"> in </span><span class="si">{obj}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
                    <span class="n">name</span><span class="o">=</span><span class="n">name</span><span class="p">,</span>
                    <span class="n">typ1</span><span class="o">=</span><span class="nb">type</span><span class="p">(</span><span class="n">value</span><span class="p">),</span>
                    <span class="n">typ2</span><span class="o">=</span><span class="nb">type</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">name</span><span class="p">)),</span>
                    <span class="n">obj</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">obj</span><span class="p">),</span>
                <span class="p">)</span>
            <span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="nb">setattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>

    <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
        <span class="nb">setattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span></div>



<div class="viewcode-block" id="from_iadd">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.from_iadd">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">from_iadd</span><span class="p">(</span><span class="n">objs</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Return True if one or more objects have attribute iadd_flag set to True.&quot;&quot;&quot;</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">for</span> <span class="n">o</span> <span class="ow">in</span> <span class="n">objs</span><span class="p">:</span>
            <span class="k">if</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="s2">&quot;iadd_flag&quot;</span><span class="p">,</span> <span class="kc">False</span><span class="p">):</span>
                <span class="k">return</span> <span class="kc">True</span>
        <span class="k">return</span> <span class="kc">False</span>
    <span class="k">except</span> <span class="ne">TypeError</span><span class="p">:</span>
        <span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">objs</span><span class="p">,</span> <span class="s2">&quot;iadd_flag&quot;</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span></div>



<div class="viewcode-block" id="set_iadd">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.set_iadd">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">set_iadd</span><span class="p">(</span><span class="n">objs</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Set iadd_flag with T/F value for a list of objects.&quot;&quot;&quot;</span>
    <span class="n">set_attr</span><span class="p">(</span><span class="n">objs</span><span class="p">,</span> <span class="s2">&quot;iadd_flag&quot;</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span></div>



<div class="viewcode-block" id="rmv_iadd">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.rmv_iadd">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">rmv_iadd</span><span class="p">(</span><span class="n">objs</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Delete iadd_flag attribute from a list of objects.&quot;&quot;&quot;</span>
    <span class="n">rmv_attr</span><span class="p">(</span><span class="n">objs</span><span class="p">,</span> <span class="s2">&quot;iadd_flag&quot;</span><span class="p">)</span></div>



<div class="viewcode-block" id="merge_dicts">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.merge_dicts">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">merge_dicts</span><span class="p">(</span><span class="n">dct</span><span class="p">,</span> <span class="n">merge_dct</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Dict merge that recurses through both dicts and updates keys.</span>

<span class="sd">    Args:</span>
<span class="sd">        dct: The dict that will be updated.</span>
<span class="sd">        merge_dct: The dict whose values will be inserted into dct.</span>

<span class="sd">    Returns:</span>
<span class="sd">        Nothing.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="n">merge_dct</span><span class="o">.</span><span class="n">items</span><span class="p">()):</span>
        <span class="k">if</span> <span class="p">(</span>
            <span class="n">k</span> <span class="ow">in</span> <span class="n">dct</span>
            <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">dct</span><span class="p">[</span><span class="n">k</span><span class="p">],</span> <span class="nb">dict</span><span class="p">)</span>
            <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">merge_dct</span><span class="p">[</span><span class="n">k</span><span class="p">],</span> <span class="n">collections</span><span class="o">.</span><span class="n">Mapping</span><span class="p">)</span>
        <span class="p">):</span>
            <span class="n">merge_dicts</span><span class="p">(</span><span class="n">dct</span><span class="p">[</span><span class="n">k</span><span class="p">],</span> <span class="n">merge_dct</span><span class="p">[</span><span class="n">k</span><span class="p">])</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">dct</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">merge_dct</span><span class="p">[</span><span class="n">k</span><span class="p">]</span></div>



<span class="c1"># Store names that have been previously assigned.</span>
<span class="n">name_heap</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="kc">None</span><span class="p">])</span>
<span class="n">prefix_counts</span> <span class="o">=</span> <span class="n">collections</span><span class="o">.</span><span class="n">Counter</span><span class="p">()</span>


<div class="viewcode-block" id="reset_get_unique_name">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.reset_get_unique_name">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">reset_get_unique_name</span><span class="p">():</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Reset the heaps that store previously-assigned names.&quot;&quot;&quot;</span>
    <span class="k">global</span> <span class="n">name_heap</span><span class="p">,</span> <span class="n">prefix_counts</span>
    <span class="n">name_heap</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="kc">None</span><span class="p">])</span>
    <span class="n">prefix_counts</span> <span class="o">=</span> <span class="n">collections</span><span class="o">.</span><span class="n">Counter</span><span class="p">()</span></div>



<span class="c1"># TODO: Rework get_unique_name().</span>
<div class="viewcode-block" id="get_unique_name">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.get_unique_name">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">get_unique_name</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="n">attrib</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">initial</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Return a name that doesn&#39;t collide with another in a list.</span>

<span class="sd">    This subrcurrent_leveline is used to generate unique part references (e.g., &quot;R12&quot;)</span>
<span class="sd">    or unique net names (e.g., &quot;N$5&quot;).</span>

<span class="sd">    Args:</span>
<span class="sd">        lst: The list of objects containing names.</span>
<span class="sd">        attrib: The attribute in each object containing the name.</span>
<span class="sd">        prefix: The prefix attached to each name.</span>
<span class="sd">        initial: The initial setting of the name (can be None or empty string).</span>

<span class="sd">    Returns:</span>
<span class="sd">        A string containing the unique name.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="c1"># Use the list id to disambiguate names of objects on different lists (e.g., parts &amp; nets).</span>
    <span class="n">lst_id</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="nb">id</span><span class="p">(</span><span class="n">lst</span><span class="p">))</span>

    <span class="n">name</span> <span class="o">=</span> <span class="n">initial</span>

    <span class="c1"># Fast processing for names that haven&#39;t been seen before.</span>
    <span class="c1"># This speeds up the most common cases for finding a new name, but doesn&#39;t</span>
    <span class="c1"># really hurt the less common cases.</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">name</span><span class="p">:</span>
        <span class="n">name</span> <span class="o">=</span> <span class="n">prefix</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">prefix_counts</span><span class="p">[</span><span class="n">lst_id</span> <span class="o">+</span> <span class="n">prefix</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">lst_id</span> <span class="o">+</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">name_heap</span><span class="p">:</span>
            <span class="n">name_heap</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">lst_id</span> <span class="o">+</span> <span class="n">name</span><span class="p">)</span>
            <span class="n">prefix_counts</span><span class="p">[</span><span class="n">lst_id</span> <span class="o">+</span> <span class="n">prefix</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
            <span class="k">return</span> <span class="n">name</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
            <span class="n">name</span> <span class="o">=</span> <span class="n">prefix</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">lst_id</span> <span class="o">+</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">name_heap</span><span class="p">:</span>
            <span class="n">name_heap</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">lst_id</span> <span class="o">+</span> <span class="n">name</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">name</span>

    <span class="c1"># Get the unique names used in the list.</span>
    <span class="n">unique_names</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="nb">getattr</span><span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">attrib</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span> <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">lst</span><span class="p">])</span>

    <span class="c1"># If the initial name is None, then create a name based on the prefix</span>
    <span class="c1"># and the smallest unused number that&#39;s available for that prefix.</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">name</span><span class="p">:</span>
        <span class="c1"># Do a binary search for a unique name formed from the prefix + number.</span>
        <span class="n">n</span> <span class="o">=</span> <span class="mi">1</span>  <span class="c1"># Starting number to append to the prefix.</span>
        <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
            <span class="c1"># Step forward in larger and larger increments looking for a name</span>
            <span class="c1"># that isn&#39;t in the list.</span>
            <span class="n">step</span> <span class="o">=</span> <span class="mi">1</span>
            <span class="k">while</span> <span class="n">prefix</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="ow">in</span> <span class="n">unique_names</span><span class="p">:</span>
                <span class="n">n</span> <span class="o">+=</span> <span class="n">step</span>
                <span class="n">step</span> <span class="o">*=</span> <span class="mi">2</span>
            <span class="c1"># If the step is 1, then the first name tried was available, so take it.</span>
            <span class="c1"># If the step is two, the next sequential name after the first name tried</span>
            <span class="c1"># was available, so take that.</span>
            <span class="k">if</span> <span class="n">step</span> <span class="ow">in</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">):</span>
                <span class="n">name</span> <span class="o">=</span> <span class="n">prefix</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
                <span class="k">break</span>
            <span class="c1"># For larger step sizes, there may be non-existent names preceding</span>
            <span class="c1"># the current value of n. So search backward starting with a large step</span>
            <span class="c1"># and making it smaller and smaller until an existing name is found.</span>
            <span class="k">while</span> <span class="p">(</span><span class="n">prefix</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">unique_names</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span><span class="n">step</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">):</span>
                <span class="n">step</span> <span class="o">//=</span> <span class="mi">2</span>
                <span class="n">n</span> <span class="o">-=</span> <span class="n">step</span>
            <span class="c1"># Go back to the start of the loop and search forward from this value</span>
            <span class="c1"># of n looking for an unused slot.</span>

            <span class="c1"># Bump prefix counter to the newest index.</span>
            <span class="n">prefix_counts</span><span class="p">[</span><span class="n">lst_id</span> <span class="o">+</span> <span class="n">prefix</span><span class="p">]</span> <span class="o">=</span> <span class="n">n</span>

    <span class="c1"># If the initial name is just a number, then prepend the prefix to it.</span>
    <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
        <span class="n">name</span> <span class="o">=</span> <span class="n">prefix</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>

    <span class="c1"># Now determine if there are any items in the list with the same name.</span>
    <span class="c1"># If the name is unique, then return it.</span>
    <span class="k">if</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">unique_names</span><span class="p">:</span>
        <span class="n">name_heap</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">lst_id</span> <span class="o">+</span> <span class="n">name</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">name</span>

    <span class="c1"># Otherwise, determine how many copies of the name are in the list and</span>
    <span class="c1"># append a number to make this name unique.</span>
    <span class="n">filter_dict</span> <span class="o">=</span> <span class="p">{</span><span class="n">attrib</span><span class="p">:</span> <span class="n">re</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="o">+</span> <span class="sa">r</span><span class="s2">&quot;_\d+&quot;</span><span class="p">}</span>
    <span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">filter_list</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="o">**</span><span class="n">filter_dict</span><span class="p">))</span>
    <span class="n">name</span> <span class="o">=</span> <span class="n">name</span> <span class="o">+</span> <span class="s2">&quot;_&quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>

    <span class="c1"># Recursively call this rcurrent_leveline using the newly-generated name to</span>
    <span class="c1"># make sure it&#39;s unique. Eventually, a unique name will be returned.</span>
    <span class="k">return</span> <span class="n">get_unique_name</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="n">attrib</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span></div>



<div class="viewcode-block" id="fullmatch">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.fullmatch">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">fullmatch</span><span class="p">(</span><span class="n">regex</span><span class="p">,</span> <span class="n">string</span><span class="p">,</span> <span class="n">flags</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Emulate python-3.4 re.fullmatch().&quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="s2">&quot;(?:&quot;</span> <span class="o">+</span> <span class="n">regex</span> <span class="o">+</span> <span class="sa">r</span><span class="s2">&quot;)\Z&quot;</span><span class="p">,</span> <span class="n">string</span><span class="p">,</span> <span class="n">flags</span><span class="o">=</span><span class="n">flags</span><span class="p">)</span></div>



<div class="viewcode-block" id="filter_list">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.filter_list">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">filter_list</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="o">**</span><span class="n">criteria</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Return a list of objects whose attributes match a set of criteria.</span>

<span class="sd">    Return a list of objects extracted from a list whose attributes match a</span>
<span class="sd">    set of criteria. The match is done using regular expressions.</span>
<span class="sd">    Example: filter_list(pins, name=&#39;io[0-9]+&#39;, direction=&#39;bidir&#39;) will</span>
<span class="sd">    return all the bidirectional pins of the component that have pin names</span>
<span class="sd">    starting with &#39;io&#39; followed by a number (e.g., &#39;IO45&#39;).</span>

<span class="sd">    If an attribute of the lst object is a list or tuple, each entry in the</span>
<span class="sd">    list/tuple will be checked for a match. Only one entry needs to match to</span>
<span class="sd">    consider the entire attribute a match. This feature is useful when</span>
<span class="sd">    searching for objects that contain a list of aliases, such as Part objects.</span>

<span class="sd">    Args:</span>
<span class="sd">        lst: The list from which objects will be extracted.</span>

<span class="sd">    Keywords Args:</span>
<span class="sd">        criteria: Keyword-argument pairs. The keyword specifies the attribute</span>
<span class="sd">            name while the argument contains the desired value of the attribute.</span>
<span class="sd">            Regardless of what type the argument is, it is always compared as if</span>
<span class="sd">            it was a string. The argument can also be a regular expression that</span>
<span class="sd">            must match the entire string created from the attribute of the list</span>
<span class="sd">            object.</span>

<span class="sd">    Returns:</span>
<span class="sd">        A list of objects whose attributes match *all* the criteria.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="nf">strmatch</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">flags</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Case-insensitive string matching.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">a</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="n">b</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>

    <span class="c1"># Determine what type of matching is needed: string or regex.</span>
    <span class="c1"># If no do_str_match, then do regex matching.</span>
    <span class="c1"># If do_str_match is False, then do regex matching.</span>
    <span class="c1"># If do_str_match is True, then do simple string matching.</span>
    <span class="k">if</span> <span class="n">criteria</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s2">&quot;do_str_match&quot;</span><span class="p">,</span> <span class="kc">False</span><span class="p">):</span>
        <span class="n">compare_func</span> <span class="o">=</span> <span class="n">strmatch</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">compare_func</span> <span class="o">=</span> <span class="n">fullmatch</span>

    <span class="c1"># Place any matching objects from the list in here.</span>
    <span class="n">extract</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">lst</span><span class="p">:</span>
        <span class="c1"># Compare an item&#39;s attributes to each of the criteria.</span>
        <span class="c1"># Break current_level of the criteria loop and don&#39;t add the item to the extract</span>
        <span class="c1"># list if *any* of the item&#39;s attributes *does not* match.</span>
        <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="n">criteria</span><span class="o">.</span><span class="n">items</span><span class="p">()):</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">attr_val</span> <span class="o">=</span> <span class="n">to_list</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">k</span><span class="p">))</span>
            <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
                <span class="c1"># If the attribute doesn&#39;t exist, then that&#39;s a non-match.</span>
                <span class="k">break</span>

            <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">Rgx</span><span class="p">):</span>
                <span class="c1"># Loop through the list of attribute values. If at least one</span>
                <span class="c1"># value matches the current criterium, then break from the</span>
                <span class="c1"># criteria loop and extract this item.</span>
                <span class="k">for</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">attr_val</span><span class="p">:</span>
                    <span class="c1"># This is an Rgx, so use fullmatch().</span>
                    <span class="k">if</span> <span class="n">fullmatch</span><span class="p">(</span>
                        <span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">),</span>
                        <span class="nb">str</span><span class="p">(</span><span class="n">val</span><span class="p">),</span>
                        <span class="n">flags</span><span class="o">=</span><span class="n">re</span><span class="o">.</span><span class="n">IGNORECASE</span> <span class="o">|</span> <span class="n">re</span><span class="o">.</span><span class="n">MULTILINE</span> <span class="o">|</span> <span class="n">re</span><span class="o">.</span><span class="n">DOTALL</span><span class="p">,</span>
                    <span class="p">):</span>
                        <span class="c1"># One of the list of values matched, so break from this</span>
                        <span class="c1"># loop and do not execute the break in the</span>
                        <span class="c1"># loop&#39;s else clause.</span>
                        <span class="k">break</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="c1"># If we got here, then none of the values in the attribute</span>
                    <span class="c1"># list matched the current criterium. Therefore, break current_level</span>
                    <span class="c1"># of the criteria loop and don&#39;t add this list item to</span>
                    <span class="c1"># the extract list.</span>
                    <span class="k">break</span>

            <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="n">basestring</span><span class="p">)):</span>
                <span class="c1"># Loop through the list of attribute values. If at least one</span>
                <span class="c1"># value matches the current criterium, then break from the</span>
                <span class="c1"># criteria loop and extract this item.</span>
                <span class="k">for</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">attr_val</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">compare_func</span><span class="p">(</span>
                        <span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">),</span>
                        <span class="nb">str</span><span class="p">(</span><span class="n">val</span><span class="p">),</span>
                        <span class="n">flags</span><span class="o">=</span><span class="n">re</span><span class="o">.</span><span class="n">IGNORECASE</span> <span class="o">|</span> <span class="n">re</span><span class="o">.</span><span class="n">MULTILINE</span> <span class="o">|</span> <span class="n">re</span><span class="o">.</span><span class="n">DOTALL</span><span class="p">,</span>
                    <span class="p">):</span>
                        <span class="c1"># One of the list of values matched, so break from this</span>
                        <span class="c1"># loop and do not execute the break in the</span>
                        <span class="c1"># loop&#39;s else clause.</span>
                        <span class="k">break</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="c1"># If we got here, then none of the values in the attribute</span>
                    <span class="c1"># list matched the current criterium. Therefore, break current_level</span>
                    <span class="c1"># of the criteria loop and don&#39;t add this list item to</span>
                    <span class="c1"># the extract list.</span>
                    <span class="k">break</span>

            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># Check non-integer, non-string attributes.</span>
                <span class="k">if</span> <span class="n">v</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">attr_val</span><span class="p">:</span>
                    <span class="k">break</span>

        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># If we get here, then all the item attributes matched and the</span>
            <span class="c1"># for criteria loop didn&#39;t break, so add this item to the</span>
            <span class="c1"># extract list.</span>
            <span class="n">extract</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">extract</span></div>



<div class="viewcode-block" id="expand_indices">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.expand_indices">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">expand_indices</span><span class="p">(</span><span class="n">slice_min</span><span class="p">,</span> <span class="n">slice_max</span><span class="p">,</span> <span class="n">match_regex</span><span class="p">,</span> <span class="o">*</span><span class="n">indices</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Expand a list of indices into a list of integers and strings.</span>

<span class="sd">    This function takes the indices used to select pins of parts and</span>
<span class="sd">    lines of buses and returns a flat list of numbers and strings.</span>
<span class="sd">    String and integer indices are put in the list unchanged, but</span>
<span class="sd">    slices are expanded into a list of integers before entering the</span>
<span class="sd">    final list.</span>

<span class="sd">    Args:</span>
<span class="sd">        slice_min: The minimum possible index.</span>
<span class="sd">        slice_max: The maximum possible index (used for slice indices).</span>
<span class="sd">        match_regex: If true,</span>
<span class="sd">        indices: A list of indices made up of numbers, slices, text strings.</span>

<span class="sd">    Returns:</span>
<span class="sd">        A linear list of all the indices made up only of numbers and strings.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="kn">from</span> <span class="nn">.logger</span> <span class="kn">import</span> <span class="n">active_logger</span>

    <span class="k">def</span> <span class="nf">expand_slice</span><span class="p">(</span><span class="n">slc</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Expand slice notation.&quot;&quot;&quot;</span>

        <span class="c1"># Get bounds for slice.</span>
        <span class="n">start</span><span class="p">,</span> <span class="n">stop</span><span class="p">,</span> <span class="n">step</span> <span class="o">=</span> <span class="n">slc</span><span class="o">.</span><span class="n">indices</span><span class="p">(</span><span class="n">slice_max</span><span class="p">)</span>
        <span class="n">start</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="nb">max</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">slice_min</span><span class="p">),</span> <span class="n">slice_max</span><span class="p">)</span>
        <span class="n">stop</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="nb">max</span><span class="p">(</span><span class="n">stop</span><span class="p">,</span> <span class="n">slice_min</span><span class="p">),</span> <span class="n">slice_max</span><span class="p">)</span>

        <span class="c1"># Do this if it&#39;s a downward slice (e.g., [7:0]).</span>
        <span class="k">if</span> <span class="n">start</span> <span class="o">&gt;</span> <span class="n">stop</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">slc</span><span class="o">.</span><span class="n">start</span> <span class="ow">and</span> <span class="n">slc</span><span class="o">.</span><span class="n">start</span> <span class="o">&gt;</span> <span class="n">slice_max</span><span class="p">:</span>
                <span class="n">active_logger</span><span class="o">.</span><span class="n">raise_</span><span class="p">(</span>
                    <span class="ne">IndexError</span><span class="p">,</span>
                    <span class="s2">&quot;Index current_level of range (</span><span class="si">{}</span><span class="s2"> &gt; </span><span class="si">{}</span><span class="s2">)!&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
                        <span class="n">slc</span><span class="o">.</span><span class="n">start</span><span class="p">,</span> <span class="n">slice_max</span>
                    <span class="p">),</span>
                <span class="p">)</span>
            <span class="c1"># Count down from start to stop.</span>
            <span class="n">stop</span> <span class="o">=</span> <span class="n">stop</span> <span class="o">-</span> <span class="n">step</span>
            <span class="n">step</span> <span class="o">=</span> <span class="o">-</span><span class="n">step</span>

        <span class="c1"># Do this if it&#39;s a normal (i.e., upward) slice (e.g., [0:7]).</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">slc</span><span class="o">.</span><span class="n">stop</span> <span class="ow">and</span> <span class="n">slc</span><span class="o">.</span><span class="n">stop</span> <span class="o">&gt;</span> <span class="n">slice_max</span><span class="p">:</span>
                <span class="n">active_logger</span><span class="o">.</span><span class="n">raise_</span><span class="p">(</span>
                    <span class="ne">IndexError</span><span class="p">,</span>
                    <span class="s2">&quot;Index current_level of range (</span><span class="si">{}</span><span class="s2"> &gt; </span><span class="si">{}</span><span class="s2">)!&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
                        <span class="n">slc</span><span class="o">.</span><span class="n">stop</span><span class="p">,</span> <span class="n">slice_max</span>
                    <span class="p">),</span>
                <span class="p">)</span>
            <span class="c1"># Count up from start to stop</span>
            <span class="n">stop</span> <span class="o">+=</span> <span class="n">step</span>

        <span class="c1"># Create the sequence of indices.</span>
        <span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">stop</span><span class="p">,</span> <span class="n">step</span><span class="p">))</span>

    <span class="k">def</span> <span class="nf">explode</span><span class="p">(</span><span class="n">bus_str</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Explode a bus into its separate lines.</span>

<span class="sd">        This function takes a bus expression like &quot;ADDR[0:3]&quot; and returns</span>
<span class="sd">        &quot;ADDR0,ADDR1,ADDR2,ADDR3&quot;. It also works if the order is reversed,</span>
<span class="sd">        e.g. &quot;ADDR[3:0]&quot; returns &quot;ADDR3,ADDR2,ADDR1,ADDR0&quot;. If the input</span>
<span class="sd">        string is not a valid bus expression, then the string is returned</span>
<span class="sd">        in a one-element list.</span>

<span class="sd">        Args:</span>
<span class="sd">            bus_str: A string containing a bus expression like &quot;D[0:3]&quot;.</span>

<span class="sd">        Returns:</span>
<span class="sd">            A list of bus lines like [&#39;D0&#39;, &#39;D1&#39;, &#39;D2&#39;, &#39;D3&#39;] or a one-element</span>
<span class="sd">            list with the original input string if it&#39;s not a valid bus expression.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="n">bus</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;^(.+)\[([0-9]+):([0-9]+)\](.*)$&quot;</span><span class="p">,</span> <span class="n">bus_str</span><span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">bus</span><span class="p">:</span>
            <span class="k">return</span> <span class="p">[</span><span class="n">bus_str</span><span class="p">]</span>  <span class="c1"># Not a valid bus expression, so return input string.</span>

        <span class="c1"># What follows must be a bus expression.</span>
        <span class="n">beg_bus_name</span> <span class="o">=</span> <span class="n">bus</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        <span class="n">begin_num</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">bus</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span>
        <span class="n">end_num</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">bus</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">3</span><span class="p">))</span>
        <span class="n">end_bus_name</span> <span class="o">=</span> <span class="n">bus</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
        <span class="nb">dir</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="nb">int</span><span class="p">(</span><span class="n">begin_num</span> <span class="o">&gt;</span> <span class="n">end_num</span><span class="p">)]</span>  <span class="c1"># Bus indexes increasing or decreasing?</span>
        <span class="n">bus_pin_nums</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="n">begin_num</span><span class="p">,</span> <span class="n">end_num</span> <span class="o">+</span> <span class="nb">dir</span><span class="p">,</span> <span class="nb">dir</span><span class="p">))</span>

        <span class="c1"># If the bus string starts with an alpha, then require that any match in the</span>
        <span class="c1"># string must be preceded by a non-alpha or the start of the string.</span>
        <span class="c1"># But if the string starts with a non-alpha, then whatever precedes the</span>
        <span class="c1"># match in the string is ignored.</span>
        <span class="k">if</span> <span class="n">match_regex</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">beg_bus_name</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">isalpha</span><span class="p">():</span>
                <span class="n">non_alphanum</span> <span class="o">=</span> <span class="s2">&quot;((?&lt;=[^0-9a-zA-Z])|^)&quot;</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">non_alphanum</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">non_alphanum</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>

        <span class="c1"># The character following a bus index must be non-numeric so that &quot;B1&quot; does</span>
        <span class="c1"># not also match &quot;B11&quot;. This must also be a look-ahead assertion so it</span>
        <span class="c1"># doesn&#39;t consume any of the string.</span>
        <span class="k">if</span> <span class="n">match_regex</span><span class="p">:</span>
            <span class="n">non_num</span> <span class="o">=</span> <span class="s2">&quot;(?=[^0-9]|$)&quot;</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">non_num</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>

        <span class="k">return</span> <span class="p">[</span>
            <span class="n">non_alphanum</span> <span class="o">+</span> <span class="n">beg_bus_name</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="o">+</span> <span class="n">non_num</span> <span class="o">+</span> <span class="n">end_bus_name</span>
            <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">bus_pin_nums</span>
        <span class="p">]</span>

    <span class="c1"># Expand each index and add it to the list.</span>
    <span class="n">ids</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">indx</span> <span class="ow">in</span> <span class="n">flatten</span><span class="p">(</span><span class="n">indices</span><span class="p">):</span>
        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">indx</span><span class="p">,</span> <span class="nb">slice</span><span class="p">):</span>
            <span class="n">ids</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">expand_slice</span><span class="p">(</span><span class="n">indx</span><span class="p">))</span>
        <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">indx</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
            <span class="n">ids</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">indx</span><span class="p">)</span>
        <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">indx</span><span class="p">,</span> <span class="n">Rgx</span><span class="p">):</span>
            <span class="c1"># Rgx might contain multiple indices with a separator.</span>
            <span class="k">for</span> <span class="nb">id</span> <span class="ow">in</span> <span class="n">re</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">INDEX_SEPARATOR</span><span class="p">,</span> <span class="n">indx</span><span class="p">):</span>
                <span class="c1"># If the id is a valid bus expression, then the exploded bus lines</span>
                <span class="c1"># are added to the list of ids. If not, the original id is</span>
                <span class="c1"># added to the list.</span>
                <span class="n">ids</span><span class="o">.</span><span class="n">extend</span><span class="p">((</span><span class="n">Rgx</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">explode</span><span class="p">(</span><span class="nb">id</span><span class="o">.</span><span class="n">strip</span><span class="p">())))</span>
        <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">indx</span><span class="p">,</span> <span class="n">basestring</span><span class="p">):</span>
            <span class="c1"># String might contain multiple indices with a separator.</span>
            <span class="k">for</span> <span class="nb">id</span> <span class="ow">in</span> <span class="n">re</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">INDEX_SEPARATOR</span><span class="p">,</span> <span class="n">indx</span><span class="p">):</span>
                <span class="c1"># If the id is a valid bus expression, then the exploded bus lines</span>
                <span class="c1"># are added to the list of ids. If not, the original id is</span>
                <span class="c1"># added to the list.</span>
                <span class="n">ids</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">explode</span><span class="p">(</span><span class="nb">id</span><span class="o">.</span><span class="n">strip</span><span class="p">()))</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">active_logger</span><span class="o">.</span><span class="n">raise_</span><span class="p">(</span>
                <span class="ne">TypeError</span><span class="p">,</span> <span class="s2">&quot;Unknown type in index: </span><span class="si">{}</span><span class="s2">.&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">indx</span><span class="p">))</span>
            <span class="p">)</span>

    <span class="c1"># Return the completely expanded list of indices.</span>
    <span class="k">return</span> <span class="n">ids</span></div>



<div class="viewcode-block" id="expand_buses">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.expand_buses">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">expand_buses</span><span class="p">(</span><span class="n">pins_nets_buses</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Take list of pins, nets, and buses and return a list of only pins and nets.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="c1"># This relies on the fact that a bus is an iterable of its nets,</span>
    <span class="c1"># and pins/nets return an iterable containing only a single pin/net.</span>
    <span class="n">pins_nets</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">pnb</span> <span class="ow">in</span> <span class="n">pins_nets_buses</span><span class="p">:</span>
        <span class="n">pins_nets</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">pnb</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">pins_nets</span></div>



<div class="viewcode-block" id="find_num_copies">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.find_num_copies">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">find_num_copies</span><span class="p">(</span><span class="o">**</span><span class="n">attribs</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Return the number of copies to make based on the number of attribute values.</span>

<span class="sd">    Keyword Args:</span>
<span class="sd">        attribs: Dict of Keyword/Value pairs for setting object attributes.</span>
<span class="sd">            If the value is a scalar, then the number of copies is one.</span>
<span class="sd">            If the value is a list/tuple, the number of copies is the</span>
<span class="sd">            length of the list/tuple.</span>

<span class="sd">    Returns:</span>
<span class="sd">        The length of the longest value in the dict of attributes.</span>

<span class="sd">    Raises:</span>
<span class="sd">        Exception if there are two or more list/tuple values with different</span>
<span class="sd">        lengths that are greater than 1. (All attribute values must be scalars</span>
<span class="sd">        or lists/tuples of the same length.)</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="kn">from</span> <span class="nn">.logger</span> <span class="kn">import</span> <span class="n">active_logger</span>

    <span class="n">num_copies</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
    <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="n">attribs</span><span class="o">.</span><span class="n">items</span><span class="p">()):</span>
        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">)):</span>
            <span class="n">num_copies</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">v</span><span class="p">))</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">num_copies</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

    <span class="n">num_copies</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">num_copies</span><span class="p">)</span>
    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">num_copies</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">2</span><span class="p">:</span>
        <span class="n">active_logger</span><span class="o">.</span><span class="n">raise_</span><span class="p">(</span>
            <span class="ne">ValueError</span><span class="p">,</span>
            <span class="s2">&quot;Mismatched lengths of attributes: </span><span class="si">{}</span><span class="s2">!&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">num_copies</span><span class="p">),</span>
        <span class="p">)</span>
    <span class="k">elif</span> <span class="nb">len</span><span class="p">(</span><span class="n">num_copies</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="ow">and</span> <span class="nb">min</span><span class="p">(</span><span class="n">num_copies</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
        <span class="n">active_logger</span><span class="o">.</span><span class="n">raise_</span><span class="p">(</span>
            <span class="ne">ValueError</span><span class="p">,</span>
            <span class="s2">&quot;Mismatched lengths of attributes: </span><span class="si">{}</span><span class="s2">!&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">num_copies</span><span class="p">),</span>
        <span class="p">)</span>

    <span class="k">try</span><span class="p">:</span>
        <span class="k">return</span> <span class="nb">max</span><span class="p">(</span><span class="n">num_copies</span><span class="p">)</span>
    <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
        <span class="k">return</span> <span class="mi">0</span>  <span class="c1"># If the list if empty.</span></div>



<div class="viewcode-block" id="norecurse">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.norecurse">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">norecurse</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Decorator that keeps a function from recursively calling itself.</span>

<span class="sd">    Parameters</span>
<span class="sd">    ----------</span>
<span class="sd">    f: function</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="c1"># If a function&#39;s name is on the stack twice (once for the current call</span>
        <span class="c1"># and a second time for the previous call), then return withcurrent_level</span>
        <span class="c1"># executing the function.</span>
        <span class="k">if</span> <span class="nb">len</span><span class="p">([</span><span class="mi">1</span> <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">traceback</span><span class="o">.</span><span class="n">extract_stack</span><span class="p">()</span> <span class="k">if</span> <span class="n">l</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="n">f</span><span class="o">.</span><span class="vm">__name__</span><span class="p">])</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
            <span class="k">return</span> <span class="kc">None</span>

        <span class="c1"># Otherwise, not a recursive call so execute the function and return result.</span>
        <span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">func</span></div>



<div class="viewcode-block" id="TriggerDict">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.TriggerDict">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">class</span> <span class="nc">TriggerDict</span><span class="p">(</span><span class="nb">dict</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;This dict triggers a function when one of its entries changes.&quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

        <span class="c1"># Create a dict of functions that will be run if their associated</span>
        <span class="c1"># key entries change. The functions arguments will be the main</span>
        <span class="c1"># TriggerDict, the key, and the new value to be stored.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">trigger_funcs</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>

    <span class="k">def</span> <span class="fm">__setitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">k</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">trigger_funcs</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">v</span> <span class="o">!=</span> <span class="bp">self</span><span class="p">[</span><span class="n">k</span><span class="p">]:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">trigger_funcs</span><span class="p">[</span><span class="n">k</span><span class="p">](</span><span class="bp">self</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__setitem__</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span></div>



<div class="viewcode-block" id="is_binary_file">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.is_binary_file">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">is_binary_file</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Return true if a file contains binary (non-text) characters.&quot;&quot;&quot;</span>
    <span class="n">text_chars</span> <span class="o">=</span> <span class="nb">bytearray</span><span class="p">({</span><span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">27</span><span class="p">}</span> <span class="o">|</span> <span class="nb">set</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mh">0x20</span><span class="p">,</span> <span class="mh">0x100</span><span class="p">))</span> <span class="o">-</span> <span class="p">{</span><span class="mh">0x7F</span><span class="p">})</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&quot;rb&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>
            <span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span><span class="o">.</span><span class="n">translate</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">text_chars</span><span class="p">))</span>
    <span class="k">except</span> <span class="p">(</span><span class="ne">IOError</span><span class="p">,</span> <span class="ne">FileNotFoundError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">):</span>
        <span class="k">return</span> <span class="kc">False</span></div>



<span class="k">def</span> <span class="nf">is_url</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">urlparse</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="o">.</span><span class="n">scheme</span> <span class="ow">in</span> <span class="p">{</span><span class="s2">&quot;http&quot;</span><span class="p">,</span> <span class="s2">&quot;https&quot;</span><span class="p">}</span>


<div class="viewcode-block" id="find_and_open_file">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.find_and_open_file">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">find_and_open_file</span><span class="p">(</span>
    <span class="n">filename</span><span class="p">,</span> <span class="n">paths</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">ext</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">allow_failure</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">exclude_binary</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">descend</span><span class="o">=</span><span class="mi">0</span>
<span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Search for a file in list of paths, open it and return file pointer and full file name.</span>

<span class="sd">    Args:</span>
<span class="sd">        filename: Base file name (e.g., &quot;my_file&quot;).</span>
<span class="sd">        paths: List of paths to search for the file.</span>
<span class="sd">        ext: The extension for the file (e.g., &quot;.txt&quot;).</span>
<span class="sd">        allow_failure: If false, failure to find file raises and exception.</span>
<span class="sd">        exclude_binary: If true, skip files that contain binary data.</span>
<span class="sd">        descend: If 0, don&#39;t search lower-level directories. If positive, search</span>
<span class="sd">                 that many levels down for the file. If negative, descend into</span>
<span class="sd">                 subdirectories withcurrent_level limit.</span>

<span class="sd">    Returns:</span>
<span class="sd">        File pointer and file name or None, None if file could not be opened.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="kn">from</span> <span class="nn">.logger</span> <span class="kn">import</span> <span class="n">active_logger</span>

    <span class="c1"># Get the directory path from the file name. This even works with URLs.</span>
    <span class="n">fpth</span><span class="p">,</span> <span class="n">fnm</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
    <span class="n">base</span><span class="p">,</span> <span class="n">suffix</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">fnm</span><span class="p">)</span>

    <span class="c1"># Update the paths to search through based on the given file name.</span>
    <span class="k">if</span> <span class="n">is_url</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
        <span class="c1"># This is a URL. Use the URL path as the search path.</span>
        <span class="n">paths</span> <span class="o">=</span> <span class="p">[</span><span class="n">fpth</span><span class="p">]</span>
    <span class="k">elif</span> <span class="n">fpth</span><span class="p">:</span>
        <span class="c1"># The file has a leading path, so use that as the path to search in.</span>
        <span class="n">paths</span> <span class="o">=</span> <span class="p">[</span><span class="n">fpth</span><span class="p">]</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="c1"># filename was not a URL and had no path prefix path, so assume it&#39;s just a file.</span>
        <span class="c1"># Search in the set of paths provided or the current directory.</span>
        <span class="n">paths</span> <span class="o">=</span> <span class="n">paths</span> <span class="ow">or</span> <span class="p">[</span><span class="s2">&quot;.&quot;</span><span class="p">]</span>

    <span class="c1"># Get the list of file extensions to check against.</span>
    <span class="k">if</span> <span class="n">suffix</span><span class="p">:</span>
        <span class="c1"># If an explicit file extension was given, just use that.</span>
        <span class="n">exts</span> <span class="o">=</span> <span class="p">[</span><span class="n">suffix</span><span class="p">]</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">exts</span> <span class="o">=</span> <span class="n">to_list</span><span class="p">(</span><span class="n">ext</span><span class="p">)</span>

    <span class="c1"># Create the regular expression for matching against the filename.</span>
    <span class="c1"># exts = [re.escape(ext) for ext in exts]</span>
    <span class="n">match_name</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="n">base</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;(&quot;</span> <span class="o">+</span> <span class="s2">&quot;|&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">exts</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;)$&quot;</span>

    <span class="c1"># Search through the directory paths for a file whose name matches the regular expression.</span>
    <span class="k">for</span> <span class="n">path</span> <span class="ow">in</span> <span class="n">paths</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">is_url</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
            <span class="k">for</span> <span class="n">ext</span> <span class="ow">in</span> <span class="n">exts</span><span class="p">:</span>
                <span class="n">link</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">base</span> <span class="o">+</span> <span class="n">ext</span><span class="p">)</span>
                <span class="k">try</span><span class="p">:</span>
                    <span class="k">return</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">link</span><span class="p">),</span> <span class="n">link</span>
                <span class="k">except</span> <span class="n">urllib</span><span class="o">.</span><span class="n">error</span><span class="o">.</span><span class="n">HTTPError</span><span class="p">:</span>
                    <span class="c1"># File failed, so keep searching.</span>
                    <span class="k">pass</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># Search through the files in a particular directory path.</span>
            <span class="n">descent_ctr</span> <span class="o">=</span> <span class="n">descend</span>  <span class="c1"># Controls the descent through the path.</span>
            <span class="k">for</span> <span class="n">root</span><span class="p">,</span> <span class="n">dirnames</span><span class="p">,</span> <span class="n">filenames</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
                <span class="c1"># Get files in the current directory whose names match the regular expression.</span>
                <span class="k">for</span> <span class="n">fn</span> <span class="ow">in</span> <span class="p">[</span><span class="n">f</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">filenames</span> <span class="k">if</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">match_name</span><span class="p">,</span> <span class="n">f</span><span class="p">)]:</span>
                    <span class="n">abs_filename</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">fn</span><span class="p">)</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="n">exclude_binary</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">is_binary_file</span><span class="p">(</span><span class="n">abs_filename</span><span class="p">):</span>
                        <span class="k">try</span><span class="p">:</span>
                            <span class="c1"># Return the first file that matches the criteria.</span>
                            <span class="k">return</span> <span class="nb">open</span><span class="p">(</span><span class="n">abs_filename</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&quot;latin_1&quot;</span><span class="p">),</span> <span class="n">abs_filename</span>
                        <span class="k">except</span> <span class="p">(</span><span class="ne">IOError</span><span class="p">,</span> <span class="ne">FileNotFoundError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">):</span>
                            <span class="c1"># File failed, so keep searching.</span>
                            <span class="k">pass</span>
                <span class="c1"># Keep descending on this path as long as the descent counter is non-zero.</span>
                <span class="k">if</span> <span class="n">descent_ctr</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                    <span class="k">break</span>  <span class="c1"># Cease search of this path if the counter is zero.</span>
                <span class="n">descent_ctr</span> <span class="o">-=</span> <span class="mi">1</span>  <span class="c1"># Decrement the counter for the next directory level.</span>

    <span class="c1"># Couldn&#39;t find a matching file.</span>
    <span class="k">if</span> <span class="n">allow_failure</span><span class="p">:</span>
        <span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">active_logger</span><span class="o">.</span><span class="n">raise_</span><span class="p">(</span>
            <span class="ne">FileNotFoundError</span><span class="p">,</span> <span class="s2">&quot;Can&#39;t open file: </span><span class="si">{}</span><span class="s2">.</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
        <span class="p">)</span></div>



<div class="viewcode-block" id="find_and_read_file">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.find_and_read_file">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="k">def</span> <span class="nf">find_and_read_file</span><span class="p">(</span>
    <span class="n">filename</span><span class="p">,</span> <span class="n">paths</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">ext</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">allow_failure</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">exclude_binary</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">descend</span><span class="o">=</span><span class="mi">0</span>
<span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Search for a file in list of paths, open it and return its contents.</span>

<span class="sd">    Args:</span>
<span class="sd">        filename: Base file name (e.g., &quot;my_file&quot;).</span>
<span class="sd">        paths: List of paths to search for the file.</span>
<span class="sd">        ext: The extension for the file (e.g., &quot;.txt&quot;).</span>
<span class="sd">        allow_failure: If false, failure to find file raises and exception.</span>
<span class="sd">        exclude_binary: If true, skip files that contain binary data.</span>
<span class="sd">        descend: If 0, don&#39;t search lower-level directories. If positive, search</span>
<span class="sd">                 that many levels down for the file. If negative, descend into</span>
<span class="sd">                 subdirectories withcurrent_level limit.</span>

<span class="sd">    Returns:</span>
<span class="sd">        File contents and file name or None, None if file could not be opened.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">fp</span><span class="p">,</span> <span class="n">fn</span> <span class="o">=</span> <span class="n">find_and_open_file</span><span class="p">(</span>
        <span class="n">filename</span><span class="p">,</span> <span class="n">paths</span><span class="p">,</span> <span class="n">ext</span><span class="p">,</span> <span class="n">allow_failure</span><span class="p">,</span> <span class="n">exclude_binary</span><span class="p">,</span> <span class="n">descend</span>
    <span class="p">)</span>
    <span class="k">if</span> <span class="n">fp</span><span class="p">:</span>
        <span class="n">contents</span> <span class="o">=</span> <span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
        <span class="n">fp</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">contents</span> <span class="o">=</span> <span class="n">contents</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&quot;latin_1&quot;</span><span class="p">)</span>
        <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
            <span class="c1"># File contents were already decoded.</span>
            <span class="k">pass</span>
        <span class="k">return</span> <span class="n">contents</span><span class="p">,</span> <span class="n">fn</span>
    <span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span></div>



<div class="viewcode-block" id="opened">
<a class="viewcode-back" href="../../rst_output/skidl.utilities.html#skidl.utilities.opened">[docs]</a>
<span class="nd">@export_to_all</span>
<span class="nd">@contextmanager</span>
<span class="k">def</span> <span class="nf">opened</span><span class="p">(</span><span class="n">f_or_fn</span><span class="p">,</span> <span class="n">mode</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Yields an opened file or file-like object.</span>

<span class="sd">    Args:</span>
<span class="sd">       file_or_filename: Either an already opened file or file-like</span>
<span class="sd">           object, or a filename to open.</span>
<span class="sd">       mode: The mode to open the file in.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">f_or_fn</span><span class="p">,</span> <span class="n">basestring</span><span class="p">):</span>
        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">f_or_fn</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
            <span class="k">yield</span> <span class="n">f</span>
    <span class="k">elif</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">f_or_fn</span><span class="p">,</span> <span class="s2">&quot;fileno&quot;</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">mode</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;+&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span> <span class="o">==</span> <span class="n">f_or_fn</span><span class="o">.</span><span class="n">mode</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;+&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">):</span>
            <span class="c1"># same mode, can reuse file handle</span>
            <span class="k">yield</span> <span class="n">f_or_fn</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># open in new mode</span>
            <span class="k">with</span> <span class="n">os</span><span class="o">.</span><span class="n">fdopen</span><span class="p">(</span><span class="n">f_or_fn</span><span class="o">.</span><span class="n">fileno</span><span class="p">(),</span> <span class="n">mode</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
                <span class="k">yield</span> <span class="n">f</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span>
            <span class="s2">&quot;argument must be a filename or a file-like object (is: </span><span class="si">{}</span><span class="s2">)&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
                <span class="nb">type</span><span class="p">(</span><span class="n">f_or_fn</span><span class="p">)</span>
            <span class="p">)</span>
        <span class="p">)</span></div>

</pre></div>

            <div class="clearer"></div>
          </div>
        </div>
      </div>
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
<search id="searchbox" style="display: none" role="search">
  <h3 id="searchlabel">Quick search</h3>
    <div class="searchformwrapper">
    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>
    </div>
</search>
<script>document.getElementById('searchbox').style.display = "block"</script>
        </div>
      </div>
      <div class="clearer"></div>
    </div>
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../../genindex.html" title="General Index"
             >index</a></li>
        <li class="right" >
          <a href="../../py-modindex.html" title="Python Module Index"
             >modules</a> |</li>
        <li class="nav-item nav-item-0"><a href="../../index.html">SKiDL 1.2.2 documentation</a> &#187;</li>
          <li class="nav-item nav-item-1"><a href="../index.html" >Module code</a> &#187;</li>
        <li class="nav-item nav-item-this"><a href="">skidl.utilities</a></li> 
      </ul>
    </div>
    <div class="footer" role="contentinfo">
    &#169; Copyright 2016-2024, Dave Vandenbout.
      Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 7.3.7.
    </div>
  </body>
</html>